from logging.handlers import RotatingFileHandler
from flask import Flask
from flask import g
from flask import render_template
from redis import StrictRedis
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect, generate_csrf
from flask_session import Session
from config import config_dict
import logging
from info.utils.common import do_index_class, login_user_data

# # type: StrictRedis作用： 事先声明redis_store以后要保存什么类型的数据
redis = None  # type: StrictRedis
# 当app没有值的时候，我们创建一个空的数据库db对象
db = SQLAlchemy()


def setup_log(config_name):
    """日志的基本配置"""
    logging.basicConfig(level=config_dict[config_name].LOG_LEVEL)
    file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 100, backupCount=10)
    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
    file_log_handler.setFormatter(formatter)
    logging.getLogger().addHandler(file_log_handler)


def create_app(config_name):
    """app函数创建工厂, 根据传进来的config_name去创建响应的app对象"""
    setup_log(config_name)
    # 创建app实例对象
    app = Flask(__name__)
    configClass = config_dict[config_name]
    # 把配置类注册到app里面去
    app.config.from_object(configClass)
    # 创建redis实例对象, 把配置信息传进去
    # 利用全局变量, 把redis传出去

    global redis
    redis = StrictRedis(host=configClass.REDIS_HOST, port=configClass.REDIS_PORT, decode_responses=True)
    # 创建mysql数据库的实例对象
    # 懒加载, 创建加载对象
    db.init_app(app)
    # 5. 开启csrf后端保护验证机制

    # 提取cookie中的csrf_token和ajax请求头里面csrf_token进行比较验证操作
    csrf = CSRFProtect(app)

    # 添加自定义过滤器
    app.add_template_filter(do_index_class, "index_class")

    @app.after_request
    def after_request(response):
        """生成随机的csrf_toen"""
        # 调用函数生成 csrf_token
        csrf_token = generate_csrf()
        # 通过 cookie 将值传给前端
        response.set_cookie('csrf_token', csrf_token)
        return response

    # 创建session的对象 传进去app对象时, 会报错.符号不对(是因为我把SECRET_KEY导致程序错误, )
    Session(app)
    # 在这边注册蓝图函数
    # 1.这个是主页的index_bp
    from info.modules.index import index_bp
    app.register_blueprint(index_bp)
    # 1.这个是验证
    from info.modules.passport import passport_bp
    app.register_blueprint(passport_bp)
    # 1.这个是新闻页面的
    from info.modules.news import news_bp
    app.register_blueprint(news_bp)
    # 1.这个是个人页面的
    from info.modules.profile import profile_bp
    app.register_blueprint(profile_bp)
    # 1.这个是个管理员的
    from info.modules.admin import admin_bp
    app.register_blueprint(admin_bp)


    # 捕获404错误 然后返回固定的页面
    @app.errorhandler(404)
    @login_user_data
    def page_not_found(_):
        user = g.user
        data = {"user_info": user.to_dict() if user else None}

        return render_template('news/404.html', data=data)
    return app


